]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
dnd: Repick target actor if destroyed mid iteration
authorJonas Ådahl <jadahl@gmail.com>
Thu, 3 Jan 2019 10:53:13 +0000 (11:53 +0100)
committerFlorian Müllner <florian.muellner@gmail.com>
Wed, 9 Jan 2019 16:15:59 +0000 (16:15 +0000)
The picked target actor may be destroyed (e.g. hover style change
resulting in the ClutterTexture to be destroyed). If we don't handle
this, GJS will abort when it sees the exception caused by Javascript
code trying to access the destroyed target actor.

To handle it, listen on the 'destroy' signal on the target actor, and
repick, so a valid actor is passed to the next motion callback.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/632
js/ui/dnd.js

index 8483e89fce354c102ec621ada367795a470f439e..665881363ee981c4ce17b76842362a083d7c89bb 100644 (file)
@@ -411,10 +411,15 @@ var _Draggable = new Lang.Class({
         return true;
     },
 
+    _pickTargetActor() {
+        return this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
+                                                            this._dragX, this._dragY);
+    },
+
     _updateDragHover() {
         this._updateHoverId = 0;
-        let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
-                                                                  this._dragX, this._dragY);
+        let target = this._pickTargetActor();
+
         let dragEvent = {
             x: this._dragX,
             y: this._dragY,
@@ -422,6 +427,18 @@ var _Draggable = new Lang.Class({
             source: this.actor._delegate,
             targetActor: target
         };
+
+        let targetActorDestroyHandlerId;
+        let handleTargetActorDestroyClosure;
+        handleTargetActorDestroyClosure = () => {
+            target = this._pickTargetActor();
+            dragEvent.targetActor = target;
+            targetActorDestroyHandlerId =
+                target.connect('destroy', handleTargetActorDestroyClosure);
+        };
+        targetActorDestroyHandlerId =
+            target.connect('destroy', handleTargetActorDestroyClosure);
+
         for (let i = 0; i < dragMonitors.length; i++) {
             let motionFunc = dragMonitors[i].dragMotion;
             if (motionFunc) {
@@ -432,6 +449,7 @@ var _Draggable = new Lang.Class({
                 }
             }
         }
+        dragEvent.targetActor.disconnect(targetActorDestroyHandlerId);
 
         while (target) {
             if (target._delegate && target._delegate.handleDragOver) {